package cn.mengfly.testnrz.netty;

import cn.mengfly.testnrz.nio.NioDemoConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.nio.charset.StandardCharsets;

public class NettyEchoServer {
    private final int serverPort;
    ServerBootstrap b = new ServerBootstrap();

    public NettyEchoServer(int serverPort) {
        this.serverPort = serverPort;
    }


    public void runServer() {
        EventLoopGroup bossLoopGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerLoopGroup = new NioEventLoopGroup();
        try {
            b.group(bossLoopGroup, workerLoopGroup);
            b.channel(NioServerSocketChannel.class);
            b.localAddress(serverPort);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    channel.pipeline().addLast(NettyEchoServerHandler.INSTANCE);
                }
            });
            ChannelFuture sync = b.bind().sync();
            System.out.println("服务器启动成功, 监听端口：" + sync.channel().localAddress());
            final ChannelFuture closeFuture = sync.channel().closeFuture();
            closeFuture.sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossLoopGroup.shutdownGracefully();
            workerLoopGroup.shutdownGracefully();
        }

    }
    @ChannelHandler.Sharable
    public static class NettyEchoServerHandler extends ChannelInboundHandlerAdapter {

        public static final NettyEchoServerHandler INSTANCE = new NettyEchoServerHandler();

        @Override
        public void channelRead(ChannelHandlerContext ctx, final Object msg) throws Exception {
            ByteBuf in = ((ByteBuf) msg);
            System.out.println("msg type :" + (in.hasArray() ? "堆内存" : "直接内存"));
            int len = in.readableBytes();
            byte[] arr = new byte[len];
            in.getBytes(0, arr);
            System.out.println("serer received :" + new String(arr, StandardCharsets.UTF_8));
//            ((ByteBuf) msg).retain();
            System.out.println("写回前, msg.refCnt:" + ((ByteBuf) msg).refCnt());
            // 写回数据
            // 首先，这里并没有调用super.channelRead 方法，说明不进行下面的传递
            // 其次，直接调用ctx的writeAndFlush方法是向客户端返回消息，而这里会将ByteBuf的引用减一
            // 因此如果在这里还想向后传递，需要先将ByteBuf retain一下
            ChannelFuture f = ctx.writeAndFlush(msg);
            f.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) {
                    System.out.println("写回后：" + ((ByteBuf) msg).refCnt());
                }
            });
//            super.channelRead(ctx, msg);
        }
    }

    public static void main(String[] args) {
        new NettyEchoServer(NioDemoConfig.SOCKET_PORT).runServer();
    }
}
